package com.thti.mecool.client.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Future;

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;

import com.thti.mecool.client.util.Util;

import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.util.Log;

/**
 * 
 * @author weiguo.ren
 * 
 */

public class XmppManager {

  
    private Context context;

    private NotificationService.TaskSubmitter taskSubmitter;

    private NotificationService.TaskTracker taskTracker;



    private String xmppHost;

    private int xmppPort;

    private XMPPConnection connection;

    private String username;

    private String password;

    private ConnectionListener connectionListener;

    private PacketListener notificationPacketListener;

    private List<Runnable> taskList;

    private boolean running = false;

    private Future<?> futureTask;
    
    private Handler handler;

    private Thread reconnection;
    
    static NotificationManager myNotiManager;
    private SharedPreferences save_LoginInfo ;
 

    public XmppManager(NotificationService notificationService) {
        context = notificationService;
        taskSubmitter = notificationService.getTaskSubmitter();
        taskTracker = notificationService.getTaskTracker();
        save_LoginInfo = context.getSharedPreferences("LocationService", 0);
        xmppHost = save_LoginInfo.getString("host", null);
        xmppPort = save_LoginInfo.getInt("port", 0);
       
       username=save_LoginInfo.getString("userName", null);
       password=save_LoginInfo.getString("password", null);
        connectionListener = new PersistentConnectionListener(this);
       // notificationPacketListener = new NotificationPacketListener(this);
        handler = new Handler();
        taskList = new ArrayList<Runnable>();
        reconnection = new ReconnectionThread(this);
    }

    public Context getContext() {
        return context;
    }

    public void connect() {
    	Util.print("connect()...");
        submitLoginTask();
    }

    public void disconnect() {
        Util.print( "disconnect()...");
        terminatePersistentConnection();
    }

    public void terminatePersistentConnection() {
        Util.print( "terminatePersistentConnection()...");
        Runnable runnable = new Runnable() {

            final XmppManager xmppManager = XmppManager.this;

            @Override
			public void run() {
                if (xmppManager.isConnected()) {
                    Util.print( "terminatePersistentConnection()... run()");
                    xmppManager.getConnection().removePacketListener(
                            xmppManager.getNotificationPacketListener());
                    xmppManager.getConnection().disconnect();
                }
                xmppManager.runTask();
            }

        };
        addTask(runnable);
    }

    public XMPPConnection getConnection() {
        return connection;
    }

    public void setConnection(XMPPConnection connection) {
        this.connection = connection;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }
    public Handler getHandler() {
        return handler;
    }
    public void setPassword(String password) {
        this.password = password;
    }

    public ConnectionListener getConnectionListener() {
        return connectionListener;
    }

    public PacketListener getNotificationPacketListener() {
        return notificationPacketListener;
    }

    public void startReconnectionThread() {
        synchronized (reconnection) {
            if (!reconnection.isAlive()) {
                reconnection.setName("Xmpp Reconnection Thread");
                reconnection.start();
            }
        }
    }
    
    public void reregisterAccount() {
       // removeAccount();
        submitLoginTask();
        runTask();
    }

    public List<Runnable> getTaskList() {
        return taskList;
    }

    public Future<?> getFutureTask() {
        return futureTask;
    }

    public void runTask() {
        Util.print( "runTask()...");
        synchronized (taskList) {
            running = false;
            futureTask = null;
            if (!taskList.isEmpty()) {
                Runnable runnable = taskList.get(0);
                taskList.remove(0);
                running = true;
                futureTask = taskSubmitter.submit(runnable);
                if (futureTask == null) {
                    taskTracker.decrease();
                }
            }
        }
        taskTracker.decrease();
        Util.print( "runTask()...done");
    }


    private boolean isConnected() {
        return connection != null && connection.isConnected();
    }

    private boolean isAuthenticated() {
        return connection != null && connection.isConnected()
                && connection.isAuthenticated();
    }



    private void submitConnectTask() {
        Util.print( "submitConnectTask()...");
        addTask(new ConnectTask());
    }



    private void submitLoginTask() {
        Util.print( "submitLoginTask()...");
        submitConnectTask();
        addTask(new LoginTask());
    }

    private void addTask(Runnable runnable) {
        Util.print( "addTask(runnable)...");
        taskTracker.increase();
        synchronized (taskList) {
            if (taskList.isEmpty() && !running) {
                running = true;
                futureTask = taskSubmitter.submit(runnable);
                if (futureTask == null) {
                    taskTracker.decrease();
                }
            } else {
                taskList.add(runnable);
            }
        }
        Util.print( "addTask(runnable)... done");
    }

   
    /**
     * A runnable task to connect the server. 
     */
    private class ConnectTask implements Runnable {

        final XmppManager xmppManager;

        private ConnectTask() {
            this.xmppManager = XmppManager.this;
        }

        @Override
		public void run() {
            Util.print( "ConnectTask.run()...");

            if (!xmppManager.isConnected()) {
                // Create the configuration for this new connection
                ConnectionConfiguration connConfig = new ConnectionConfiguration(
                        xmppHost, xmppPort);
                // connConfig.setSecurityMode(SecurityMode.disabled);
                connConfig.setSecurityMode(SecurityMode.required);
                connConfig.setSASLAuthenticationEnabled(false);
                connConfig.setCompressionEnabled(false);
                XMPPConnection connection = new XMPPConnection(connConfig);
                xmppManager.setConnection(connection);

                try {
                    // Connect to the server
                    connection.connect();
                    Util.print( "XMPP connected successfully");

                } catch (XMPPException e) {
                    Util.print( "XMPP connection failed" +e);
                }

                xmppManager.runTask();

            } else {
                Util.print( "XMPP connected already");
                xmppManager.runTask();
            }
        }
    }


    /**
     * A runnable task to log into the server. 
     */
    private class LoginTask implements Runnable {

        final XmppManager xmppManager;

        private LoginTask() {
            this.xmppManager = XmppManager.this;
        }

        @Override
		public void run() {
            Util.print( "LoginTask.run()...");

            if (!xmppManager.isAuthenticated()) {
            	
          
                Util.print( "username=" + username);
                Util.print( "password=" + password);

                try {
                    xmppManager.getConnection().login(
                            xmppManager.getUsername(),
                            xmppManager.getPassword());
                    Util.print( "Loggedn in successfully");

                    // connection listener
                    if (xmppManager.getConnectionListener() != null) {
                        xmppManager.getConnection().addConnectionListener(
                                xmppManager.getConnectionListener());
                    }

                	Log.i("XMPPClient", "Logged in as " +  xmppManager.getConnection().getUser());
        			// Set the status to available
        			Presence presence = new Presence(Presence.Type.available);
        			 xmppManager.getConnection().sendPacket(presence);
        			Collection<RosterEntry> entrys =  xmppManager.getConnection().getRoster()
        					.getEntries();
        			for (RosterEntry rosterEntry : entrys) {
        				
        				Util.print("1111111111111getName:  " + rosterEntry.getName());
        				Util.print("22222222getUser:   " + rosterEntry.getUser());

        			}
        			
        			PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
        			xmppManager.getConnection().addPacketListener(new PacketListener() {
        				@Override
        				public void processPacket(Packet packet) {
        					Message message = (Message) packet;
        					if (message.getBody() != null) {
        						String fromName = StringUtils.parseBareAddress(message
        								.getFrom());
        						Log.i("XMPPClient", "Got text [" + message.getBody()
        								+ "] from [" + fromName + "]");
        						
        						Log.i("message Loggedn in successfully", message.getBody());
        						
        						Intent intent=new Intent();
        						intent.setAction("com.cn.android.NotificationService");
        						intent.putExtra("msg", message.getBody().toString());
        						message.setBody(null);
        						context.sendBroadcast(intent);
        						
        					}
        				   }
        				}, filter);
        			xmppManager.runTask();
                } catch (XMPPException e) {
                    Util.print( "LoginTask.run()... xmpp error");
                    Util.print( "Failed to login to xmpp server. Caused by: "
                            + e.getMessage());
                    String INVALID_CREDENTIALS_ERROR_CODE = "401";
                    String errorMessage = e.getMessage();
                    if (errorMessage != null
                            && errorMessage
                                    .contains(INVALID_CREDENTIALS_ERROR_CODE)) {
                        xmppManager.reregisterAccount();
                        return;
                    }
                    xmppManager.startReconnectionThread();

                } catch (Exception e) {
                    Util.print( "LoginTask.run()... other error");
                    Util.print( "Failed to login to xmpp server. Caused by: "
                            + e.getMessage());
                    xmppManager.startReconnectionThread();
                }

            } else {
            	PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
    			xmppManager.getConnection().addPacketListener(new PacketListener() {
    				@Override
    				public void processPacket(Packet packet) {
    					Message message = (Message) packet;
    					if (message.getBody() != null) {
    						String fromName = StringUtils.parseBareAddress(message
    								.getFrom());
    						Log.i("XMPPClient", "Got text [" + message.getBody()
    								+ "] from [" + fromName + "]");
    						
    						Log.i("message Logged in already", message.getBody());
    						Intent intent=new Intent();
    						intent.setAction("com.cn.android.NotificationService");
    						intent.putExtra("msg", message.getBody().toString());
    						message.setBody(null);
    						context.sendBroadcast(intent);
    					}
    				   }
    				}, filter);
                Util.print( "Logged in already");
                xmppManager.runTask();
            }

        }
    }
    


}
